using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.UI;

namespace Utils.MaterialProperty.Renderer
{
    [ExecuteAlways][DisallowMultipleComponent][AddComponentMenu("Material Property/Render/Handle")]
    public class MaterialSetterHandleUniRender : MonoBehaviour
    {
        
        [SerializeField] [OnValueChanged("OnRendererChanged")]
        UnityEngine.Renderer unityRenderer;

        [SerializeField] [OnValueChanged("SetMaterial")]
        private Shader shader;

        [SerializeField] //[OnValueChanged("OnGraphicChanged")]
        private MaterialPropertyUniData[] materialPropertyUniDataArray;
        [SerializeField] [OnValueChanged("OnRendererChanged")]
        private MaterialPropertyUniRender[] materialPropertyUniArray;

        private Material mat;

        
        void Awake()
        {
            SetMaterial();
            if (unityRenderer == null)
            {
                unityRenderer = gameObject.GetComponent<UnityEngine.Renderer>();
                OnRendererChanged();
            }
        }

        private void SetMaterial()
        {
            if (shader == null)
                return;
            mat = new Material(shader);
            unityRenderer.material = mat;
        }

        private void OnRendererChanged()
        {
            Debug.Log("OnRendererChanged");
            if (materialPropertyUniArray != null)
            {
                if (materialPropertyUniDataArray.Length != materialPropertyUniArray.Length)
                {
                    materialPropertyUniDataArray  = new MaterialPropertyUniData[materialPropertyUniArray.Length];
                }
                for (var index = 0; index < materialPropertyUniArray.Length; index++)
                {
                    var setter = materialPropertyUniArray[index];
                    setter.SetRenderer(unityRenderer);
                    materialPropertyUniDataArray[index] ??= new MaterialPropertyUniData();
                    setter.ReadData(materialPropertyUniDataArray[index]);
                }
            }
        }

        private void OnDataValueChanged()
        {
            if (materialPropertyUniArray != null && materialPropertyUniDataArray!=null && materialPropertyUniDataArray.Length == materialPropertyUniArray.Length)
            {
                for (var index = 0; index < materialPropertyUniArray.Length; index++)
                {
                    var setter = materialPropertyUniArray[index];
                    setter.ApplyData(materialPropertyUniDataArray[index]);
                }
            }
        }

        private Material CurrentMaterial
        {
            get
            {
                if (mat ==null)
                {
                    SetMaterial();
                }
                return mat;
            }
        }

        public MaterialPropertyUniRender GetPropertySetter(int propertyId)
        {
            foreach (var setter in materialPropertyUniArray)
            {
                if(setter.PropertyId == propertyId)
                    return setter;
            }
            return null;
        }
        
        #if UNITY_EDITOR

        protected void Reset()
        {
            unityRenderer = GetComponent<UnityEngine.Renderer>();
        }
        #endif
        
#if UNITY_EDITOR
        protected void OnValidate()
        {
            OnDataValueChanged();
            SetContent();
        }
        
        
        [Button]
        private void ReadAllPropertySetter()
        {
            materialPropertyUniArray = gameObject.GetComponentsInChildren<MaterialPropertyUniRender>();
            OnRendererChanged();
        }
        [Button]
        private void AddSetter()
        {
            var com = gameObject.AddComponent<MaterialPropertyUniRender>();
            ReadAllPropertySetter();
        }
        
        // protected void OnDrawGizmosSelected()
        // {
        //     OnGraphicChanged();
        //     SetContent();
        // }
#endif
        
        void SetContent()
        {
            if (CurrentMaterial == null)
            {
                return;
            }
            
            if (materialPropertyUniArray == null || materialPropertyUniArray.Length == 0 )
            {
                return;
            }
            foreach (var setter in materialPropertyUniArray)
            {
                setter.SetMaterialProperty();
            }
        }

        public void ApplyChange()
        {
            SetContent();
        }
    } 
}
